package com.example.demo.serviceImpl.user;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.UUID;
import com.example.demo.dao.user.UserDao;
import com.example.demo.dao.user.WorkerReportDao;
import com.example.demo.dao.user.WorkerTaskDao;
import com.example.demo.po.task.Task;
import com.example.demo.po.user.User;
import com.example.demo.service.coreport.CoreportService;
import com.example.demo.service.report.ReportService;
import com.example.demo.service.task.RecommendService;
import com.example.demo.service.task.TaskService;
import com.example.demo.service.user.UserService;
import com.example.demo.utils.Constant;
import com.example.demo.utils.Recommender;
import com.example.demo.utils.UserHolder;
import com.example.demo.vo.ResultVO;
import com.example.demo.vo.StrategyVO;
import com.example.demo.vo.task.TaskSimpleVO;
import com.example.demo.vo.task.TaskVO;
import com.example.demo.vo.user.UserRoleVO;
import com.example.demo.vo.user.UserVO;
import com.example.demo.vo.user.WorkerTaskVO;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;


@Service
public class  UserServiceImpl implements UserService {

    @Resource
    UserDao userDao;
    @Resource
    WorkerTaskDao workerTaskDao;
    @Resource
    WorkerReportDao workerReportDao;
    @Resource
    TaskService taskService;
    @Resource
    ReportService reportService;
    @Resource
    CoreportService coreportService;
    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Resource
    RecommendService recommendService;

    Recommender recommender=Recommender.getInstance();

    @Override
    public ResultVO<UserVO> userRegister(UserVO userVO) {
        String username=userVO.getUsername();
        if(userDao.selectUserByName(username)!=null){
            return new ResultVO<UserVO>(-1,"用户名已存在");
        }
        userDao.insertUser(userVO);
        return new ResultVO<UserVO>(1,"创建成功",userVO);
    }

    @Override
    public ResultVO<UserRoleVO> userLogin(UserVO userVO) {
        String username=userVO.getUsername();
        String password=userVO.getPassword();
        if(userDao.selectUserByName(username)==null){
            return new ResultVO<UserRoleVO>(-1,"用户不存在");
        }
        User user = userDao.selectUserByName(username);
        if(!user.getPassword().equals(password)){
            return new ResultVO<UserRoleVO>(-1,"密码错误");
        }
        // 7.1.随机生成token，作为登录令牌
        String token = UUID.randomUUID().toString(true);
        // 7.2.将User对象转为HashMap存储
        Map<String, Object> userMap = BeanUtil.beanToMap(user, new HashMap<>(),
                //自定义修改，将所有字段转为字符串，避免id是long存不进redis
                CopyOptions.create()
                        .setIgnoreNullValue(true)
                        //设置value存取
                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
        // 7.3.存储
        String tokenKey = Constant.LOGIN_USER_KEY + token;
        stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
        // 7.4.设置token有效期
        stringRedisTemplate.expire(tokenKey, Constant.LOGIN_USER_TTL, TimeUnit.MINUTES);
        UserRoleVO res=new UserRoleVO(user);
        res.setToken(token);
        return new ResultVO<UserRoleVO>(1,"登录成功",res);
    }

    @Override
    public ResultVO<UserVO> getUser(String username) {
        if(userDao.selectUserByName(username)==null){
            return new ResultVO<UserVO>(-1,"用户名不存在",new UserVO());
        }
        User user = userDao.selectUserByName(username);
        return new ResultVO<UserVO>(1,"查询成功",new UserVO(user));
    }

    @Override
    public ResultVO<WorkerTaskVO> getTakeTaskState(String username,int tid) {
        if(workerTaskDao.selectTakeTaskStateByWorker(username,tid)==null){
            return new ResultVO<WorkerTaskVO>(1,"未接取该任务",new WorkerTaskVO(0));
        }
        return new ResultVO<WorkerTaskVO>(1,"查询成功",new WorkerTaskVO(workerTaskDao.selectTakeTaskStateByWorker(username,tid)));
    }

    @Override
    public ResultVO<WorkerTaskVO> setTakeTaskState(WorkerTaskVO workerTaskVO) {
        if(workerTaskDao.selectTakeTaskStateByWorker(workerTaskVO.getUsername(),workerTaskVO.getTid())!=null){
            workerTaskDao.updateTakeTaskState(workerTaskVO);
        }else {
            String username=workerTaskVO.getUsername();
            workerTaskDao.insertWorkerTask(userDao.selectUserByName(username).getUid(),workerTaskVO.getTid());
            taskService.updateCurrentWorkerById(workerTaskVO.getTid());
            Task task=taskService.getTaskById(workerTaskVO.getTid());
            userDao.updateTakeTaskNum(username);
            if(task.getType()==1){
                userDao.updatePreferencePerformance(username);
            }else {
                userDao.updatePreferenceFunction(username);
            }
        }
        recommendService.ignoreRecommend(workerTaskVO.getTid());
        return new ResultVO<WorkerTaskVO>(1,"设置成功",workerTaskVO);
    }

    @Override
    public User getUserByName(String username) {
        return userDao.selectUserByName(username);
    }

    @Override
    public ResultVO<StrategyVO> submitStrategy(StrategyVO strategyVO) {
        recommender = Recommender.getInstance();
        String strategy=strategyVO.getStrategy();
        if(strategy.length()!=3){
            return new ResultVO<StrategyVO>(-1,"提交格式错误",strategyVO);
        }
        recommender.setStrategy(strategy.substring(0,1).equals("1"),
                strategy.substring(1,2).equals("1"),
                strategy.substring(2).equals("1"));
        return new ResultVO<StrategyVO>(1,"设置成功",strategyVO);
    }

    @Override
    public ResultVO<StrategyVO> getCurrentStrategy() {
        recommender=Recommender.getInstance();
        return new ResultVO<StrategyVO>(1,"查询成功",new StrategyVO(recommender.getStrategy()));
    }

    @Override
    public String getNameByUid(int uid) {
        return userDao.selectNameByUid(uid);
    }

    @Override
    public ResultVO<List<TaskVO>> getRecommendTaskByUser(String username) {

        List<TaskVO> taskVOS = taskService.getAllValidTaskByUser(username);
        UserVO userVO = new UserVO(userDao.selectUserByName(username));
        if(taskVOS.size()==0){
            return new ResultVO<List<TaskVO>>(-1, "无正在进行任务", new ArrayList<TaskVO>());
        }
        List<TaskVO> res = recommender.getRecommendedTasks(userVO,taskVOS);
        return new ResultVO<List<TaskVO>>(1,"查询成功",res);
    }

    @Override
    public void updateDevice(String username, int deviceInfo) {
        switch (deviceInfo){
            case 0:
                userDao.updateDeviceWindows(username);
                break;
            case 1:
                userDao.updateDeviceMac(username);
                break;
            case 2:
                userDao.updateDeviceLinux(username);
                break;
            case 3:
                userDao.updateDeviceAndroid(username);
                break;
            case 4:
                userDao.updateDeviceIos(username);
                break;
        }
    }

    @Override
    public void updateAbility(String username, int difficulty) {
        userDao.updateAbility(username,difficulty);
    }

    @Override
    public void updateTakeTaskNum(String username) {
        userDao.updateTakeTaskNum(username);
    }

    @Override
    public double calculateActive(String username) {
        int reNum = reportService.getRecentReportNumByUser(username);
        int coNum = coreportService.getRecentCoreportNumByUser(username);
        double active = sigmoidFunc((2*reNum+coNum)/7.0);
        return active;
    }

        public double sigmoidFunc(double x){
        double ey = Math.pow(Math.E,-x);
        return 1/(1+ey);
    }


    @Override
    public String test() {
        return "haha";
    }

    @Override
    public List<User> getAllWorkers() {
        return userDao.selectAllWorkers();
    }

    @Override
    public List<Integer> getReportIdByWorker(int uid) {
        return workerReportDao.selectReportIdByWorker(uid);
    }
}
